package model

import (
	"errors"
	"fmt"
	"github.com/go-gin-admin/global"
	"github.com/go-gin-admin/util"
	"github.com/jinzhu/gorm"
)

type IUser interface {
	AddUser() (int64, error)                                                        // 增加用户
	UpdateUser() error                                                              // 更改用户
	GetUserList(pageIndex int64, pageSize int64, deptId int64) (interface{}, error) // 获取用户
	DeleteUser(userId int64) error                                                  // 删除用户
	LoginByUserNameAndPassWord() (string, error)                                    // 用户登录
}

type User struct {
	UserInfo
	RoleIds  []int64  `json:"roleIds"`  // 角色组
	RoleKeys []string `json:"roleKeys"` // 角色组
	DeptName string   `json:"deptName"` // 部门名称
}

type UserInfo struct {
	UserId   int64  `json:"userId" gorm:"primary_key"`  // 用户id
	Username string `json:"username"`                   // 用户名称
	Password string `json:"password"`                   // 密码
	NickName string `json:"nickName"`                   // 昵称
	Phone    string `json:"phone"`                      // 手机号码
	Salt     string `json:"salt"`                       // 盐
	Avatar   string `json:"avatar"`                     // 头像
	Gender   string `json:"gender"`                     // 性别
	Email    string `json:"email"`                      // 邮箱
	Remark   string `json:"remark"`                     // 备注
	DeptId   int64  `json:"deptId"`                     // 部门id
	JobId    int64  `json:"jobId"`                      // 岗位id
	DelFlag  string `json:"delFlag" gorm:"default:'0'"` // 删除标识符
	BaseModel
}

func (u *User) LoginByUserNameAndPassWord() (string, error) {
	// 根据用户名称查询用户
	user, err := GetUserByUsername(u.Username)
	if err != nil {
		return "", err
	}
	// 判断user是否存在
	if user.UserId <= 0 {
		return "", errors.New("用户不存在")
	}
	// 判断密码是否相等
	if user.Password != u.Password {
		return "", errors.New("密码错误")
	}
	// 生成token返回
	token, err := util.GenToken(user.Username, user.RoleKeys)
	if err != nil {
		return "", err
	}
	return token, nil
}

// 增加用户
func (u *User) AddUser() (int64, error) {
	tx := global.GDB.Begin()
	// 添加sys_user 表
	table := tx.Table("sys_user")
	userInfo := UserInfo{
		UserId:   u.UserId,
		Username: u.Username,
		Password: u.Password,
		NickName: u.NickName,
		Phone:    u.Phone,
		Salt:     u.Salt,
		Avatar:   u.Avatar,
		Gender:   u.Gender,
		Email:    u.Email,
		Remark:   u.Remark,
		DeptId:   u.DeptId,
		JobId:    u.JobId,
		DelFlag:  u.DelFlag,
		BaseModel: BaseModel{
			CreateTime: u.CreateTime,
			UpdateTime: u.UpdateTime,
		},
	}
	if err := table.Create(&userInfo).Error; err != nil {
		tx.Rollback()
		return 0, err
	}

	// 添加sys_user_role 表
	sqlStr := "INSERT INTO sys_user_role (user_id, role_id) VALUES "
	for i := 0; i < len(u.RoleIds); i++ {
		sqlStr += fmt.Sprintf("(%d, %d),", userInfo.UserId, u.RoleIds[i])
	}
	sqlStr = sqlStr[0:(len(sqlStr) - 1)]
	if err := tx.Exec(sqlStr).Error; err != nil {
		tx.Rollback()
		return 0, err
	}
	tx.Commit()
	return userInfo.UserId, nil
}

func (u *User) GetUserList(pageIndex int64, pageSize int64, deptId int64) (interface{}, error) {
	m := make(map[string]interface{})
	var total int64
	users := make([]User, 0, pageSize)
	table := global.GDB.Table("sys_user su").Joins("LEFT JOIN sys_dept sd ON su.dept_id = sd.dept_id").Where(" su.del_flag = ?", "0")
	table = table.Select("su.user_id, su.username, su.password, su.nick_name, su.phone, su.salt, su.avatar, su.gender, su.email, su.remark, su.dept_id, su.job_id, su.create_time, su.update_time, su.del_flag, sd.dept_name")
	if deptId != 0 {
		table = table.Where("su.dept_id = ?", deptId)
		// 获取总条数
		if err := table.Count(&total).Error; err != nil {
			return nil, err
		}
	} else {
		// 获取总条数
		if err := table.Count(&total).Error; err != nil {
			return nil, err
		}
	}
	if err := table.Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&users).Error; err != nil {
		return nil, err
	}

	m["item"] = users
	m["total"] = total
	return m, nil
}

// 更新用户
func (u *User) UpdateUser() error {
	tx := global.GDB.Begin()
	// 更新user表
	table := tx.Table("sys_user").Where("user_id = ?", u.UserId)
	if err := table.Updates(map[string]interface{}{"username": u.Username, "password": u.Password, "nick_name": u.NickName, "phone": u.Phone, "gender": u.Gender, "email": u.Email, "remark": u.Remark, "dept_id": u.DeptId, "job_id": u.JobId, "update_time": u.UpdateTime}).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 删除user_role表数据
	if err := tx.Exec("DELETE FROM sys_user_role WHERE user_id = ?", u.UserId).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 增加user_role表
	sqlStr := "INSERT INTO sys_user_role (user_id, role_id) VALUES "
	for i := 0; i < len(u.RoleIds); i++ {
		sqlStr += fmt.Sprintf("(%d, %d),", u.UserId, u.RoleIds[i])
	}
	sqlStr = sqlStr[0:(len(sqlStr) - 1)]
	if err := tx.Exec(sqlStr).Error; err != nil {
		return err
	}
	tx.Commit()
	return nil
}

// 删除用户
func (u *User) DeleteUser(userId int64) error {
	if err := global.GDB.Table("sys_user").Where("user_id = ?", userId).Update("del_flag", "1").Error; err != nil {
		return err
	}
	return nil
}

// 根据用户名称查询用户信息
func GetUserByUsername(userName string) (User, error) {
	var user User
	table := global.GDB.Table("sys_user").Where("del_flag = ?", "0").Where("username = ?", userName)
	if err := table.Select("user_id, username, password, nick_name, phone, salt, avatar, gender, email, remark, dept_id, job_id, create_time, update_time, del_flag").First(&user).Error; err != nil {
		// 判断错误
		switch {
		case err == gorm.ErrRecordNotFound:
			// 说明没有找到
			return user, nil
		case err != nil:
			return user, err
		}
	}
	// 根据用户id获取用户角色
	rolekeys, err := getRoleByUserId(user.UserId)
	if err != nil {
		return user, err
	}
	user.RoleKeys = rolekeys
	return user, nil
}

// 根据用户id获取所有的用户角色
func getRoleByUserId(userId int64) ([]string, error) {
	var roleKeys []string
	table := global.GDB.Table("sys_user_role sur").Where("sur.user_id = ?", userId).Joins("LEFT JOIN sys_role sr ON sur.role_id = sr.role_id")
	// Pluck 单列
	if err := table.Select("sr.role_key").Pluck("sr.role_key", &roleKeys).Error; err != nil {
		return roleKeys, err
	}
	return roleKeys, nil
}
